using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Rendering;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.Game
{
    /// <summary>
    /// 渲染相关管理器,管理Shader，材质球，渲染等级(设备高中低)等。
    /// </summary>
    public class RenderManager : FrameMonoModule
    {
        [Serializable]
        public struct LODPrefs
        {
            public GameRender.LODLevel level;
            public LODSetting setting;
        }

        #region Variable

        private static AssetBundle _shaderBundle = null;
        private readonly Dictionary<string, Shader> _shaderDic = new Dictionary<string, Shader>();
        ResLoader _resloader;

        #endregion

        private RenderManager()
        {

        }

        [SerializeField]
        private List<LODPrefs> LODSettings = new List<LODPrefs>();
        [SerializeField]
        private List<LODPrefs> BattleLODSettings = new List<LODPrefs>();

        [SerializeField]
        private GameRender.LODLevel usingLODLevel = GameRender.LODLevel.High;
        [SerializeField]
        bool highestInEditor = true;

        bool isInBattle = false;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns></returns>
        public UniTask InitRenderManager()
        {
            if (_resloader == null)
            {
                _resloader = ResLoader.Create();
            }

            return LoadShaderBundle();
        }

        public void SetLODLevel(int level)
        {
            usingLODLevel = (GameRender.LODLevel)level;
            SetUsingLODSetting();
        }

        public void SetLODLevel(GameRender.LODLevel level)
        {
            usingLODLevel = level;
            SetUsingLODSetting();
        }

        void SetUsingLODSetting()
        {
            //编辑模式下模式使用最高品质
#if UNITY_EDITOR
            if (highestInEditor)
                usingLODLevel = GameRender.LODLevel.PC;
#endif

            var settingMap = isInBattle ? BattleLODSettings : LODSettings;
            LODSetting lod = null;
            for (int i = 0; i < settingMap.Count; i++)
            {
                if (settingMap[i].level == usingLODLevel)
                {
                    lod = settingMap[i].setting;
                    break;
                }
            }

            if (lod != null)
                GameRenderLOD.Instance.SetLODSetting(usingLODLevel, lod);
        }

        /// <summary>
        /// 加载Shader的Ab，并常驻
        /// </summary>
        public async UniTask LoadShaderBundle()
        {
            _shaderBundle = _resloader.LoadAssetBundle("Res/15_Shader" + FrameworkPath.AssetBundleExtension);
            if (_shaderBundle == null)
            {
                bool isAbMode = true;
#if UNITY_EDITOR
                if (!ResManager.EditorBundleMode)
                {
                    isAbMode = false;
                }
#endif
                if (isAbMode)
                {
                    LogGame.LogError($"[{nameof(RenderManager)}]LoadShaderBundle failed!");
                }
                return;
            }
            var loadRequest = _shaderBundle.LoadAllAssetsAsync<Shader>();
            await loadRequest;
            var shaders = loadRequest.allAssets;
            if (shaders != null)
            {
                foreach (var shaderObj in shaders)
                {
                    if (shaderObj is Shader shader)
                    {
                        _shaderDic.Add(shader.name, shader);
                    }
                }
            }

            // 预热所有的ShaderVariantCollection
            // TODO，需要收集Assets/Res/15_Shader下所有的的shader到Assets/Res/15_Shader/PreLoadShaderVariants.shadervariants里
            // 这样就可以预热所有的shader了
            var shaderVariantCollections = _shaderBundle.LoadAllAssets<ShaderVariantCollection>();
            if (shaderVariantCollections != null)
            {
                foreach (var shaderVariantCollection in shaderVariantCollections)
                {
                    shaderVariantCollection.WarmUp();
                }
            }

        }

        /// <summary>
        /// 代码调用获取ab包的Shader
        /// 接口说明：
        /// 1. 走AB模式的shader，也就是在15_Shader里的Shader，统一都要走这个接口来获取Shader，而不是直接用Shader.Find
        /// 2. 如果不是放到15_Shader里Shader，请不要走这个接口，走Shader.Find，并且Shader需要放到了ProjectSettings的GraphicsSettings里
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Shader GetShader(string name)
        {
            var shaderBundle = _shaderBundle;
#if UNITY_EDITOR
            if (!ResManager.EditorBundleMode)
            {
                return Shader.Find(name);
            }
            else
#endif
            {
                if (_shaderDic.TryGetValue(name, out var shader))
                {
                    return shader;
                }
                LogGame.LogWarning($"[{nameof(RenderManager)}]GetShader failed! shader name:{name}");
                return null;
            }
        }

        protected override void OnInit()
        {
            //设置当前品质
            SetUsingLODSetting();
        }

        protected override void OnEnterGame()
        {

        }

        protected override void OnShutdown()
        {
        }

        //进入战斗时调用
        public void OnEnterBattle()
        {
            isInBattle = true;
            //设置战斗用品质
            SetUsingLODSetting();
        }

        //退出战斗时调用
        public void OnExitBattle()
        {
            isInBattle = false;
            //设置当前品质
            SetUsingLODSetting();
        }
    }
}

